\documentclass[12pt]{report}
\usepackage{geometry}
\geometry{a4paper,scale=0.8}
\usepackage{longtable}
\usepackage{url}
\usepackage{listings}
\usepackage{graphicx}
\usepackage{float}
\usepackage{titlesec}
\usepackage{CJK}
\begin{CJK}{UTF8}{gkai}
\titleformat{\chapter}[hang]{\centering\Huge\bfseries}{\chaptername}{1em}{}
%\renewcommand{\chaptername}{第\CJKnumber{thechapter}章}
\title{Linux内核代码学习}
\author{Chuzy}
\date{2020/05/03}

\lstset{
    basicstyle          =   \small\ttfamily,          % 基本代码风格
    keywordstyle        =   \bfseries,          % 关键字风格
    commentstyle        =   \rmfamily\itshape,  % 注释的风格，斜体
    stringstyle         =   \ttfamily,  % 字符串风格
    flexiblecolumns,                % 别问为什么，加上这个
    numbers             =   left,   % 行号的位置在左边
    showspaces          =   false,  % 是否显示空格，显示了有点乱，所以不现实了
    numberstyle         =   \ttfamily,    % 行号的样式，小五号，tt等宽字体
    showstringspaces    =   false,
    captionpos          =   t,      % 这段代码的名字所呈现的位置，t指的是top上面
    frame               =   lrtb,   % 显示边框
    columns         =   flexible,     
    breaklines      =   true,
    language        =  [ANSI]C,
    escapeinside=``
}


%以上部分叫做"导言区",下面才开始写正文
\begin{document}

%先插入标题
\maketitle
\tableofcontents
\newpage 

\part{常用工具}
\chapter{GCC}
\section{内联汇编}
GCC 支持在C/C++代码中嵌入汇编代码，这些汇编代码被称作GCC Inline ASM——GCC内联汇编。基本内联汇编的格式是:
\begin{lstlisting}
__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);
\end{lstlisting}
\subsection{基本定义}
\paragraph{\_\_asm\_\_}, GCC关键字asm的宏定义;
\paragraph{\_\_volatile\_\_或volatile}, 可选, 声明 “需要原封不动的保留Instruction中的每一条指令”， 避免使用优化选项(-O)进行编译时，GCC将这个内联汇编表达式中的指令优化掉;
\paragraph{Instruction List} 汇编指令序列, 任意两个指令间要么被分号(;)分开，要么被放在两行; "Instruction List"中的寄存器写法要遵守相关规定，比如寄存器前必须使用两个百分号(\%\%)，而不是像基本汇编格式一样在寄存器前只使用一个百分号(\%)。
\paragraph{Output} 输出参数，常见形式如，"=a" (\_\_res)，它包含两个约束：等号(=)和字母a，其中等号(=)说明括号中左值表达式\_\_res是一个 Write-Only的，只能够被作为当前内联汇编的输入，而不能作为输入。而字母a是寄存器EAX / AX / AL的简写，说明\_\_res的值要从eax寄存器中获取，也就是说\_\_res = eax。
\paragraph{Input} 输入参数，常见形式如，"0" (\_\_NR\_\#\#name))，"0"是约束部分，输入参数不允许指定加号(+)约束和等号(=)约束，默认Read-Only。数字0,1,2,3,4,5,6,7,8,9 I表示和第n个操作表达式使用相同的寄存器/内存。\#\#表示连接的意思，假设name=fork，则\_\_NR\_\#\#name 对应为 \_\_NR\_fork。
\paragraph{Clobber/Modify} 有时候，你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改，希望GCC在编译时能够将这一点考虑进去。那么你就可以在Clobber/Modify域声明这些寄存器或内存。如果你在一个内联汇编语句的Clobber/Modify域向GCC声明某个寄存器内容发生了改变，GCC在编译时，如果发现这个被声明的寄存器的内容在此内联汇编语句之后还要继续使用，那么GCC会首先将此寄存器的内容保存起来，然后在此内联汇编语句的相关生成代码之后，再将其内容恢复。
\subsection{常用约束}
\paragraph{寄存器操作数约束（r）}
使用此约束指定操作数时，它们将存储在通用寄存器（GPR）中。采用以下示例：
\begin{lstlisting}[breaklines]
asm ("movl %%eax, %0\n" :"=r"(myval));
\end{lstlisting}
如果要指定寄存器，必须使用特定的寄存器约束直接指定寄存器名称。
\paragraph{内存操作数 (m)}
允许使用内存操作数，以及机器通常支持的任何类型的地址。
\paragraph{可偏移内存操作数 (o)}
允许使用内存操作数，但前提是该地址是可偏移的。即，向地址添加一个小偏移量会给出一个有效的地址。
\paragraph{不可偏移内存操作数(V)}
不可偏移的内存操作数。换句话说，任何符合“m”约束但不符合“o”约束的东西。
\paragraph{立即整数操作数(i)}
允许立即整数操作数（具有常量值的操作数）。这包括符号常量，其值仅在汇编时才知道。
\paragraph{已知数值的立即整数操作数(n)}
允许具有已知数值的立即整数操作数。许多系统不能支持小于字宽的操作数的汇编时常量。这些操作数的约束应该使用'n'而不是'i'。
\paragraph{通用操作数(g)}
允许任何寄存器，存储器或立即整数操作数，但非通用寄存器的寄存器除外。


\chapter{Vim}
\section{给Vim增加tag功能}
\subsection{安装ctags}
sudo apt-get install ctags \\
实际安装的是：exuberant-ctags
\subsection{建立文件索引}
在想要建立索引文件的文件夹目录下执行\\
sudo ctags -R *
\subsection{通过tag跳转}
运行vim的时候，必须在"tags"文件所在的目录下运行。否则，运行vim的时候还要用":set tags="命令设定"tags"文件的路径，这样vim才能找到"tags"文件。\\\\
把光标移到变量名或函数名上，然后按下"Ctrl-]"。用"Ctrl-o"退回原来的地方。
\subsection{安装taglist}
taglist的下载路径：\\
\url {https://www.vim.org/scripts/script.php?script_id=273} \\\\
解压文件，复制到vim的目录下\\
sudo cp taglist.vim /usr/share/vim/vim81/plugin/ \\
sudo cp taglist.txt /usr/share/vim/vim81/doc/
\subsection{打开和关闭taglist窗口}
启动vim，用“:TlistToggle”来打开和关闭taglist窗口；

\section{撤消与重做}
\paragraph{[n] u:} 取消一(n)个改动
\paragraph{:undo 5} 撤销5个改变
\paragraph{:undolist} 你的撤销历史
\paragraph{ctrl + r:} 重做最后的改动
\paragraph{U: } 取消当前行中所有的改动
\paragraph{:earlier 4m} 回到4分钟前
\paragraph{:later 55s} 前进55秒

\section{查找}
\paragraph{/something:} 在后面的文本中查找something
\paragraph{?something:} 在前面的文本中查找something
\paragraph{/pattern/+number:} 将光标停在包含pattern的行后面第number行上
\paragraph{/pattern/-number:} 将光标停在包含pattern的行前面第number行上
\paragraph{n: } 向后查找下一个
\paragraph{N: } 向前查找下一个

\section{剪切和复制、粘贴} 
\paragraph{[n]x: } 剪切光标右边n个字符，相当于d[n]l
\paragraph{[n]X: } 剪切光标左边n个字符，相当于d[n]h
\paragraph{y: } 复制在可视模式下选中的文本
\paragraph{yy or Y:} 复制整行文本
\paragraph{y[n]w:} 复制一(n)个词。
\paragraph{y[n]l:} 复制光标右边1(n)个字符
\paragraph{y[n]h:} 复制光标左边1(n)个字符
\paragraph{yor D:} 删除（剪切）当前位置到行尾的内容
\paragraph{d[n]w:} 删除（剪切）1(n)个单词
\paragraph{d[n]l:} 删除（剪切）光标右边1(n)个字符
\paragraph{d[n]h:} 删除（剪切）光标左边1(n)个字符
\paragraph{d0:} 删除（剪切）当前位置到行首的内容
\paragraph{[n] dd:} 删除（剪切）1(n)行
\paragraph{:m,nd<cr>} 剪切m行到n行的内容
\paragraph{d1G或dgg:} 剪切光标以上的所有行。
\paragraph{dG:} 剪切光标以下的所有行。
\paragraph{daw和das：} 剪切一个词和剪切一个句子，即使光标不在词首和句首也没关系。
\paragraph{d/f<cr>：} 这是一个比较高级的组合命令，它将删除当前位置 到下一个f之间的内容。
\paragraph{p:} 在光标之后粘贴。
\paragraph{P:} 在光标之前粘贴。

\chapter{Grep}
以递归的方式查找符合条件的文件。例如，查找指定目录/etc/acpi 及其子目录（如果存在子目录的话）下所有文件中包含字符串"update"的文件，并打印出该字符串所在行的内容，使用的命令为： \cite{ref11}
\begin{lstlisting}[breaklines]
grep -r update /etc/acpi
\end{lstlisting}

\chapter{objdump}
生成反汇编文件
\begin{lstlisting}[breaklines]
objdump a.out -dSsx > file
\end{lstlisting}

\chapter{Git、GitHub和Gitee}
\section{版本控制}
\cite{ref2}什么是“版本控制”？我为什么要关心它呢？ 版本控制是一种记录一个或若干文件内容变化，以便将来查阅特定版本修订情况的系统。如果你是位图形或网页设计师，可能会需要保存某一幅图片或页面布局文件的所有修订版本（这或许是你非常渴望拥有的功能），采用版本控制系统（VCS）是个明智的选择。 有了它你就可以将选定的文件回溯到之前的状态，甚至将整个项目都回退到过去某个时间点的状态，你可以比较文件的变化细节，查出最后是谁修改了哪个地方，从而找出导致怪异问题出现的原因，又是谁在何时报告了某个功能缺陷等等。 使用版本控制系统通常还意味着，就算你乱来一气把整个项目中的文件改的改删的删，你也照样可以轻松恢复到原先的样子。 但额外增加的工作量却微乎其微。
\paragraph{本地版本控制系统}
许多人习惯用复制整个项目目录的方式来保存不同的版本，或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单，但是特别容易犯错。有时候会混淆所在的工作目录，一不小心会写错文件或者覆盖意想外的文件。为了解决这个问题，人们很久以前就开发了许多种本地版本控制系统，大多都是采用某种简单的数据库来记录文件的历次更新差异。其中最流行的一种叫做 RCS，现今许多计算机系统上都还看得到它的踪影。RCS的工作原理是在硬盘上保存补丁集（补丁是指文件修订前后的变化）；通过应用所有的补丁，可以重新计算出各个版本的文件内容。
集中化的版本控制系统.
\paragraph{集中化的版本控制系统}
接下来人们又遇到一个问题，如何让在不同系统上的开发者协同工作？ 于是，集中化的版本控制系统（Centralized Version Control Systems，简称 CVCS）应运而生。 这类系统，诸如 CVS、Subversion 以及 Perforce 等，都有一个单一的集中管理的服务器，保存所有文件的修订版本，而协同工作的人们都通过客户端连到这台服务器，取出最新的文件或者提交更新。 多年以来，这已成为版本控制系统的标准做法。这种做法带来了许多好处，特别是相较于老式的本地 VCS 来说。 现在，每个人都可以在一定程度上看到项目中的其他人正在做些什么。 而管理员也可以轻松掌控每个开发者的权限，并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。
\paragraph{分布式版本控制系统}
事分两面，有好有坏。 这么做最显而易见的缺点是中央服务器的单点故障。 如果宕机一小时，那么在这一小时内，谁都无法提交更新，也就无法协同工作。 如果中心数据库所在的磁盘发生损坏，又没有做恰当备份，毫无疑问你将丢失所有数据——包括项目的整个变更历史，只剩下人们在各自机器上保留的单独快照。 本地版本控制系统也存在类似问题，只要整个项目的历史记录被保存在单一位置，就有丢失所有历史更新记录的风险。于是分布式版本控制系统（Distributed Version Control System，简称 DVCS）面世了。 在这类系统中，像 Git、Mercurial、Bazaar 以及 Darcs 等，客户端并不只提取最新版本的文件快照， 而是把代码仓库完整地镜像下来，包括完整的历史记录。 这么一来，任何一处协同工作用的服务器发生故障，事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作，实际上都是一次对代码仓库的完整备份。更进一步，许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此，你就可以在同一个项目中，分别和不同工作小组的人相互协作。 你可以根据需要设定不同的协作流程，比如层次模型式的工作流，而这在以前的集中式系统中是无法实现的。
\section{Git}
Linux内核开源项目有着为数众多的参与者。绝大多数的Linux内核维护工作都花在了提交补丁和保存归档的繁琐事务上（1991－2002年间）。到2002年，整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码。到了2005年，开发BitKeeper的商业公司同Linux内核开源社区的合作关系结束，他们收回了Linux内核社区免费使用BitKeeper的权力。这就迫使Linux开源社区（特别是Linux的缔造者Linus Torvalds）基于使用BitKeeper时的经验教训，开发出自己的版本系统。自诞生于2005年以来，Git日臻成熟完善，在高度易用的同时，仍然保留着初期设定的目标。它的速度飞快，极其适合管理大项目，有着令人难以置信的非线性分支管理系统。
\subsection{Git和SVN}
\paragraph{区别1} 最核心的区别Git是分布式的，而Svn不是分布的。能理解这点，上手会很容易，声明一点Git并不是目前唯一的分布式版本控制系统，还有比如Mercurial等，所以说它们差不许多。话说回来Git跟Svn一样有自己的集中式版本库和Server端，但Git更倾向于分布式开发，因为每一个开发人员的电脑上都有一个Local Repository,所以即使没有网络也一样可以Commit，查看历史版本记录，创建项 目分支等操作，等网络再次连接上Push到Server端。从上面看GIt真的很棒，但是GIt adds Complexity, 刚开始使用会有些疑惑，因为需要建两个Repositories(Local Repositories 和 Remote Repositories),指令很多，除此之外你需要知道哪些指令在Local Repository，哪些指令在Remote Repository。
\paragraph{区别2} Git把内容按元数据方式存储，而SVN是按文件：因为,.git目录是处于你的机器上的一个克隆版的版本库，它拥有中心版本库上所有的东西，例如标签，分支，版本记录等。.git目录的体积大小跟.svn比较，你会发现它们差距很大。
\paragraph{区别3} Git没有一个全局版本号，而SVN有：目前为止这是跟SVN相比Git缺少的最大的一个特征。
\paragraph{区别4} Git的内容的完整性要优于SVN: GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性，确保在遇到磁盘故障和网络问题时降低对版本库的破坏。
\paragraph{区别5} Git下载下来后，在OffLine状态下可以看到所有的Log,SVN不可以。
\paragraph{区别6} 刚开始用时很狗血的一点，SVN必须先Update才能Commit,忘记了合并时就会出现一些错误，git还是比较少的出现这种情况。
\paragraph{区别7} 克隆一份全新的目录以同样拥有五个分支来说，SVN是同时复製5个版本的文件,也就是说重复五次同样的动作。而Git只是获取文件的每个版本的 元素，然后只载入主要的分支(master)在我的经验,克隆一个拥有将近一万个提交(commit),五个分支,每个分支有大约1500个文件的 SVN,耗了将近一个小时！而Git只用了区区的1分钟！
\paragraph{区别8} 版本库（repository):SVN只能有一个指定中央版本库。当这个中央版本库有问题时，所有工作成员都一起瘫痪直到版本库维修完毕或者新的版本库设立完成。而 Git可以有无限个版本库。或者，更正确的说法，每一个Git都是一个版本库，区别是它们是否拥有活跃目录（Git Working Tree）。如果主要版本库（例如：置於GitHub的版本库）发生了什麼事，工作成员仍然可以在自己的本地版本库（local repository）提交，等待主要版本库恢复即可。工作成员也可以提交到其他的版本库！
\paragraph{区别9} 分支（Branch）在SVN，分支是一个完整的目录。且这个目录拥有完整的实际文件。如果工作成员想要开啟新的分支，那将会影响“全世界”！每个人都会拥有和你一样的分支。如果你的分支是用来进行破坏工作（安检测试），那将会像传染病一样,你改一个分支，还得让其他人重新切分支重新下载，十分狗血。而 Git，每个工作成员可以任意在自己的本地版本库开啟无限个分支。举例：当我想尝试破坏自己的程序（安检测试），并且想保留这些被修改的文件供日后使用， 我可以开一个分支，做我喜欢的事。完全不需担心妨碍其他工作成员。只要我不合并及提交到主要版本库，没有一个工作成员会被影响。等到我不需要这个分支时， 我只要把它从我的本地版本库删除即可。无痛无痒。Git的分支名是可以使用不同名字的。例如：我的本地分支名为OK，而在主要版本库的名字其实是master。最值得一提，我可以在Git的任意一个提交点（commit point）开启分支！（其中一个方法是使用gitk –all 可观察整个提交记录，然后在任意点开啟分支。）
\paragraph{区别10} 提交（Commit）在SVN，当你提交你的完成品时，它将直接记录到中央版本库。当你发现你的完成品存在严重问题时，你已经无法阻止事情的发生了。如果网路中断，你根本没办法提交！而Git的提交完全属於本地版本库的活动。而你只需“推”（git push）到主要版本库即可。Git的“推”其实是在执行“同步”（Sync）。
\paragraph{总结：} 
SVN的特点是简单，只是需要一个放代码的地方时用是OK的。Git的特点版本控制可以不依赖网络做任何事情，对分支和合并有更好的支持(当然这是开发者最关心的地方)，不过想各位能更好使用它，需要花点时间尝试下。\cite{ref3}
\section{Github}
GitHub是一个面向开源及私有 软件项目的托管平台，因为只支持 Git 作为唯一的版本库格式进行托管，故名 GitHub。 GitHub 于 2008 年 4 月 10 日正式上线，除了 Git 代码仓库托管及基本的 Web 管理界面以外，还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱（报表）、代码片段分享（Gist）等功能。目前，其注册用户已经超过350万，托管版本数量也是非常之多，其中不乏知名开源项目 Ruby on Rails、jQuery、python 等。GitHub 去年为漏洞支付了 16.6 万美元赏金。 2018年6月，GitHub被微软以75亿美元的价格收购。\cite{ref4}
GitHub 可以托管各种 git 库，并提供一个 Web 界面，但与其它像 SourceForge 或 Google Code 这样的服务不同，GitHub 的独特卖点在于从另外一个项目进行分支的简易性。为一个项目贡献代码非常简单：首先点击项目站点的 "fork" 按钮，然后将代码检出并将修改加入到刚才分出的代码库中，最后通过内建的 "pull request" 机制向项目负责人申请代码合并。\cite{ref5}
2018年10月26日，微软以75亿美元收购GitHub交易已完成。10月29日，微软开发者服务副总裁奈特·弗里德曼(Nat Friedman)将成为GitHub的新一任CEO。\cite{ref6}
\section{Gitee}
Gitee （中文名：码云 ，原名 Git@OSC ）是开源中国推出的基于 Git 的代码托管服务。目前已经托管超过 600 万的项目\cite{ref7}。
github 实在太慢了，gitee 访问速度快。
\section{Git操作-新建仓库}
\paragraph{注册Gitee或Github} Github速度实在太慢，建议登录Gitee官网注册帐号。官网：\url {https://gitee.com}
\paragraph{安装git} 
sudo apt-get install git
\paragraph{配置全局环境\\} 
git config --global user.name "your user name" \\
git config --global user.email "your mail address"
\paragraph{创建本地仓库xxx} 
mkdir xxx
\paragraph{初始化本地仓库\\} 
cd xxx \\
git init
\paragraph{把xxx目录下的文件加入仓库} 
git add .
\paragraph{提交变更} 
git commit -m "first commit"
\paragraph{把新建立的仓库推送到Gitee\\} 
git remote add origin https://gitee.com/username/xxx.git
\paragraph{推送本地仓库内容\\} 
git push -u origin master
\section{Git操作-克隆仓库}
\paragraph{克隆Gitee远程仓库} 
git clone https://gitee.com//username/xxx.git
\section{Git操作-从本地更新到远程}
\paragraph{添加整个文件夹} 
git add directory/
\paragraph{添加一个文件夹下的内容} 
git add .
\paragraph{提交变更到本地仓库} 
git commit -a -m "massage"
\paragraph{推送到Gitee}
git push -u origin master
\section{Git操作-从远程更新到本地}
\paragraph{获取更新并合并}
git pull origin master
\paragraph{获取更新不合并} 
git fetch origin master

\chapter{文件比较工具meld}
meld类似于windows中的beyondcompare\\\\
sudo apt install meld

\chapter{磁盘映像文件}
\paragraph{磁盘映像创建} 
dd if=/dev/zero of=hdc.img bs=512 count=83300
\paragraph{磁盘映像分区} 
fdisk -c=dos -u=cylinders -l hdc.img
\paragraph{观察磁盘映像中的内容} 
od -w4 -N 512 -x hdc.img

\end{CJK}
\end{document}
